package cn.xinfei.xdecision.engine.runner.executor.strategy.branch;

import cn.xinfei.xdecision.common.model.component.strategyout.StrategyOutput;
import cn.xinfei.xdecision.common.model.enginex.po.EngineNode;
import cn.xinfei.xdecision.common.model.enginex.runner.Sandbox;
import cn.xinfei.xdecision.common.utils.enums.enginex.ConditionValueTypeEnum;
import cn.xinfei.xdecision.common.utils.enums.enginex.NodeTypeEnum;
import cn.xinfei.xdecision.common.vo.FieldInfoVo;
import cn.xinfei.xdecision.constant.EngineResultEnum;
import cn.xinfei.xdecision.engine.runner.context.PipelineContextHolder;
import cn.xinfei.xdecision.engine.runner.context.XDecisionContext;
import cn.xinfei.xdecision.engine.runner.executor.NodeHandler;
import cn.xinfei.xdecision.engine.runner.executor.XRunner;
import cn.xinfei.xdecision.engine.runner.executor.model.StateTransmitModel;
import cn.xinfei.xdecision.engine.runner.executor.strategy.EngineNodeRunner;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.*;

import static cn.xinfei.xdecision.engine.runner.executor.model.InterVariableConstant.INTER_GROUP_NODE_CODE;
import static cn.xinfei.xdecision.engine.runner.executor.model.InterVariableConstant.INTER_STREAM_NODE_CODE;

@XRunner
@Slf4j
@Service
public class SandboxProportion extends EngineNodeRunner {

    @Override
    public String getServiceName() {
        return EngineNodeRunner.PRE + NodeTypeEnum.SANDBOX.getType();
    }

    public Map<String, FieldInfoVo> getInputFieldInfo(NodeHandler nodeHandler) {
        return null;
    }

    @Override
    public Map<String, StrategyOutput> getTerminalOutputFieldInfo(NodeHandler nodeHandler) {

        Map<String, StrategyOutput> fieldVos = new HashMap<>();

        return fieldVos;
    }
    @Override
    public Map<String, StrategyOutput> getOutputFieldInfo(NodeHandler nodeHandler) {
        Map<String, StrategyOutput> outputResult = new HashMap<>();
        StrategyOutput output = new StrategyOutput();
        output.setFieldCode(INTER_STREAM_NODE_CODE);
        output.setFieldValue(INTER_STREAM_NODE_CODE);
        output.setVarValueType(2);
        output.setStage(2);//过程
        output.setValueType(ConditionValueTypeEnum.VARIABLE.getCode());
        outputResult.put(INTER_STREAM_NODE_CODE, output);
        return outputResult;
    }

    @Override
    public StateTransmitModel runNode(NodeHandler nodeHandler) {
        EngineNode engineNode = nodeHandler.getEngineNode();
        String nodeCode = engineNode.getNodeCode();
        String nextNodeCode = null;
        if (null != engineNode.getNodeScript()) {
            List<Sandbox> list = JSON.parseArray(engineNode.getNodeScript(), Sandbox.class);
            //监控中心-- 节点配置信息记录(不需要策略层面的监控)
            nextNodeCode = getNextNodeCode(list, engineNode);
        }

        if (StringUtils.isNotEmpty(nextNodeCode)) {
            PipelineContextHolder.putInContext(nodeCode, INTER_STREAM_NODE_CODE, nextNodeCode);
        }else{
            log.error("分流节点没有获取到nextNodeCode信息");
            return XDecisionContext.getContext().getStateContext().setEngineResultEnum(EngineResultEnum.EXCEPTION_NO_NEXT_END);
        }
        log.info("执行分流节点 runNode nodeCode:{},nextNode:{}", nodeCode, nextNodeCode);
        return XDecisionContext.getContext().getStateContext().setNextNodeCode(nextNodeCode);
    }

    private String getNextNodeCode(List<Sandbox> list, EngineNode engineNode) {
        int num = 0;//随机生成的数
        int startNum = 0;
        int endNum = 0;
        String nextNodeCode = null;
        for (int i = 0; i < list.size(); i++) {
            Sandbox sandbox = list.get(i);
            endNum = startNum + sandbox.getProportion();
            if (num == 0) {
                num = getRandoms(0, sandbox.getSum(), 1)[0];
            }
            int[] range = getRandoms(startNum, endNum, sandbox.getProportion());
            for (int j = 0; j < range.length; j++) {
                if (range[j] == num) {
                    if (StringUtils.isBlank(sandbox.getNextNode())) {
                        List<Sandbox> sblist = JSON.parseArray(engineNode.getNodeJson(), Sandbox.class);
                        for (Sandbox sb : sblist) {
                            if (sb.getSandbox() == sandbox.getSandbox()) {
                                sandbox.setNextNode(sb.getNextNode());
                                break;
                            }
                        }
                    }

                    nextNodeCode = sandbox.getNextNode();
                    break;
                }
            }
            startNum = endNum;
        }
        return nextNodeCode;
    }

    /**
     * 根据min和max随机生成count个不重复的随机数组
     *
     * @param min
     * @param max
     * @param count
     * @return int[]
     */
    public int[] getRandoms(int min, int max, int count) {
        int[] randoms = new int[count];
        List<Integer> listRandom = new ArrayList<Integer>();

        if (count > (max - min + 1)) {
            return null;
        }
        // 将所有的可能出现的数字放进候选list
        for (int i = min; i < max; i++) {
            listRandom.add(i);
        }
        // 从候选list中取出放入数组，已经被选中的就从这个list中移除
        for (int i = 0; i < count; i++) {
            int index = getRandom(0, listRandom.size() - 1);
            randoms[i] = listRandom.get(index);
            listRandom.remove(index);
        }

        return randoms;
    }

    /**
     * 根据min和max随机生成一个范围在[min,max]的随机数，包括min和max
     *
     * @param min
     * @param max
     * @return int
     */
    public int getRandom(int min, int max) {
        Random random = new Random();
        return random.nextInt(max - min + 1) + min;
    }




    @Override
    public boolean terminalCondition(NodeHandler nodeHandler, Map<String, Object> nodeOutput, Map<String, Object> nodeInput) {
        return false;
    }
}
